﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Interop;

namespace MouseExtender.Logic.Common
{
    /// <summary> This class allows you to manage a hotkey </summary>
    public class GlobalKeyboardHotkeys : IDisposable
    {
        [DllImport("user32", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool RegisterHotKey(IntPtr hwnd, int id, int fsModifiers, int vk);
        [DllImport("user32", SetLastError = true)]
        public static extern int UnregisterHotKey(IntPtr hwnd, int id);
        [DllImport("kernel32", SetLastError = true)]
        public static extern short GlobalAddAtom(string lpString);
        [DllImport("kernel32", SetLastError = true)]
        public static extern short GlobalDeleteAtom(short nAtom);

   

        public const int WM_HOTKEY = 0x312;
        private MouseExtender.MainWindow _mainWindow = null;

        public GlobalKeyboardHotkeys(MouseExtender.MainWindow window)
        {
            _mainWindow = window;
            _handle = new WindowInteropHelper(window).Handle;
            ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage;
            window.Closing += MainWindow_Closing;
        }

        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            ComponentDispatcher.ThreadPreprocessMessage -= ComponentDispatcher_ThreadPreprocessMessage;
            UnregisterGlobalHotKey();
        }

        private void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled)
        {
            if (msg.message == WM_HOTKEY)
            {
                //TODO do it async, also move all winapi externals to single class (NativeMethods)
                Hardcodet.Wpf.TaskbarNotification.Interop.Point p = new Hardcodet.Wpf.TaskbarNotification.Interop.Point();
                if (Hardcodet.Wpf.TaskbarNotification.Interop.WinApi.GetCursorPos(ref p))
                {
                    _mainWindow.ShowInPoint(new Point(p.X, p.Y));
                    handled = true;
                }
            }

        }

        /// <summary> handle of the current process </summary>
        private IntPtr _handle;

        /// <summary> the ID for the hotkey </summary>
        public short HotkeyID
        {
            get;
            private set;
        }

        /// <summary> register the hotkey </summary>
        private void RegisterGlobalHotKey(int hotkey, int modifiers, IntPtr handle)
        {
            UnregisterGlobalHotKey();
            _handle = handle;
            RegisterGlobalHotKey(hotkey, modifiers);
        }

        /// <summary> register the hotkey </summary>
        public void RegisterGlobalHotKey(int hotkey, int modifiers)
        {
            UnregisterGlobalHotKey();

            try
            {
                // use the GlobalAddAtom API to get a unique ID (as suggested by MSDN docs)
                string atomName = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString("X8") + this.GetType().FullName;
                HotkeyID = GlobalAddAtom(atomName);
                if (HotkeyID == 0)
                {
                    throw new Exception("Unable to generate unique hotkey ID. Error: " +
                                        Marshal.GetLastWin32Error());
                }
                // register the hotkey, throw if any error
                if (!RegisterHotKey(_handle, HotkeyID, modifiers, hotkey))
                {
                    throw new Exception("Unable to register hotkey. Error: " + Marshal.GetLastWin32Error());
                }
            }
            catch (Exception e)
            {
                // clean up if hotkey registration failed
                UnregisterGlobalHotKey();
                Console.WriteLine(e);
            }
        }

        /// <summary> unregister the hotkey </summary>
        public void UnregisterGlobalHotKey()
        {
            if (HotkeyID != 0)
            {
                UnregisterHotKey(_handle, HotkeyID);
                // clean up the atom list
                GlobalDeleteAtom(HotkeyID);
                HotkeyID = 0;
            }
        }

        public void Dispose()
        {
            UnregisterGlobalHotKey();
        }
    }
}
